#ifndef __ATOM_H
#define __ATOM_H
#include "stdtype.h"

/// ------------------------------------------------------------------------ atom swp

/**
 * function [ mx_atom_swp ] implementation
 * @prototype: mx_usize_t mx_atom_swp (mx_usize_t newv, volatile mx_usize_pt var);
 *      @param newv: the new value need to shift-in `var`
 *      @param var: the target variable (memroy)
 *      @return: the old value of `var`
 * @desc: atomic shift-in the new value and shift-out the old value
 */
mx_usize_t mx_atom_swp (mx_usize_t newv, volatile mx_usize_pt var);

/* atomic set a value to `target` variable and the compare the original value
   of `target` whether equal to `test` */
mx_bool_t mx_atom_set8test (mx_usize_pt target, mx_usize_t val, mx_usize_t test);

/// ------------------------------------------------------------------------ atom flag

/* value of mx_atom_flag_t.flag */
#define MX_ATOM_FLAG_LOCKED 0x5AU   // mark the atom flag has been locked
#define MX_ATOM_FLAG_UNLOCK 0x00U   // mark the atom flag not be locked

/**
 * atom flag struct definition
 */
typedef struct
{
    mx_usize_t lock;                // the atomic flag's lock
    mx_void_pt owner;               // the atomic flag's owner,
                                    // the values must be a unique identifier
} mx_atom_flag_t, *mx_atom_flag_pt;

/* initialize the specified atom flag */
void mx_atom_flag_init (mx_atom_flag_pt pflag);
/* lock the specified atomic flag */
mx_bool_t mx_atom_flag_lock (mx_atom_flag_pt pflag, mx_void_pt owner);
/* unlock the specified atomic flag */
void mx_atom_flag_unlock (mx_atom_flag_pt pflag, mx_void_pt owner);

/// ------------------------------------------------------------------------ atom calculate

#include "spinlock.h"

/**
 * atom operation struct definition
 */
typedef struct
{
    volatile mx_usize_t operand;    // the operands used in the atomic operation process
    mx_spinlock_t spinlock;
} mx_atom_t, *mx_atom_pt;

/* initialize the atomic operation descriptor */
void mx_atom_init (mx_atom_pt patom);
/* get the atomic value */
mx_usize_t mx_atom_get (mx_atom_pt patom);
/* atomic addition operation */
void mx_atom_add (mx_atom_pt patom, mx_usize_t val);
/* atomic addition operation and test whether the value after the operation
   is equal to the specified value */
mx_bool_t mx_atom_add8test (mx_atom_pt patom, mx_usize_t val, mx_usize_t test);
/* atomic subtraction operation */
void mx_atom_sub (mx_atom_pt patom, mx_usize_t val);
/* atomic subtraction operation and test whether the value after the operation
   is equal to the specified value */
mx_bool_t mx_atom_sub8test (mx_atom_pt patom, mx_usize_t val, mx_usize_t test);

#endif
